using AutoMapper;
using MediatR;
using RBAC.Domain.SmartHealthcare.Hosiptial;
using RBAC.ErrorCode;
using RBAC.Interstructrue;
using RBAC.Interstructrue.Base;
using SmartHealthcare.Write.Api.Application.Command.HospitalExpense;
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace SmartHealthcare.Write.Api.Application.Handler.HospitalExpense
{
    /// <summary>
    /// 创建住院费用记录处理器
    /// </summary>
    public class CreateHospitalExpenseHandler : IRequestHandler<CreateHospitalExpenseCommand, APIResult<long>>
    {
        private readonly IBaseRepository<HospitalExpenseModel> expenseRepository;
        private readonly IBaseRepository<InpatientRegistryModel> registryRepository;
        private readonly IBaseRepository<PrepaymentModel> prepaymentRepository;
        private readonly RBACDbContext dbContext;
        private readonly ILogger<CreateHospitalExpenseHandler> logger;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="expenseRepository">住院费用记录仓储</param>
        /// <param name="registryRepository">住院登记仓储</param>
        /// <param name="prepaymentRepository">预交款仓储</param>
        /// <param name="dbContext">数据库上下文</param>
        /// <param name="logger">日志记录器</param>
        public CreateHospitalExpenseHandler(
            IBaseRepository<HospitalExpenseModel> expenseRepository,
            IBaseRepository<InpatientRegistryModel> registryRepository,
            IBaseRepository<PrepaymentModel> prepaymentRepository,
            RBACDbContext dbContext,
            ILogger<CreateHospitalExpenseHandler> logger)
        {
            this.expenseRepository = expenseRepository;
            this.registryRepository = registryRepository;
            this.prepaymentRepository = prepaymentRepository;
            this.dbContext = dbContext;
            this.logger = logger;
        }

        /// <summary>
        /// 处理创建住院费用记录请求
        /// </summary>
        /// <param name="request">请求参数</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>新创建的记录ID</returns>
        public Task<APIResult<long>> Handle(CreateHospitalExpenseCommand request, CancellationToken cancellationToken)
        {
            APIResult<long> result = new APIResult<long>();

            try
            {
                logger.LogInformation($"开始创建住院费用记录，患者：{request.PatientName}，项目：{request.ItemName}，金额：{request.UnitPrice * request.Quantity}");

                // 验证住院登记是否存在
                var registry = registryRepository.GetModel(request.InpatientRegistryId);
                if (registry == null || registry.IsDeleted)
                {
                    logger.LogWarning($"住院登记不存在，ID：{request.InpatientRegistryId}");
                    result.Code = APIEnums.Fail;
                    result.Msg = "住院登记不存在";
                    return Task.FromResult(result);
                }

                // 计算总金额、医保报销金额和自费金额
                decimal totalAmount = request.UnitPrice * request.Quantity;
                decimal insuranceAmount = totalAmount * (request.InsuranceRatio / 100);
                decimal selfPayAmount = totalAmount - insuranceAmount;

                // 创建住院费用记录
                var expense = new HospitalExpenseModel
                {
                    MedicalCard = request.MedicalCard ?? string.Empty,
                    PatientName = request.PatientName ?? "未知患者",
                    InpatientRegistryId = request.InpatientRegistryId,
                    DepartmentName = request.DepartmentName ?? "未知科室",
                    ItemId = request.ItemId,
                    ItemName = request.ItemName ?? "未知项目",
                    ItemType = request.ItemType ?? "其他",
                    Specification = request.Specification ?? string.Empty,
                    UnitPrice = request.UnitPrice,
                    Quantity = request.Quantity,
                    TotalAmount = totalAmount,
                    InsuranceRatio = request.InsuranceRatio,
                    InsuranceAmount = insuranceAmount,
                    SelfPayAmount = selfPayAmount,
                    BatchNumber = request.BatchNumber ?? string.Empty,
                    ExpiryDate = request.ExpiryDate,
                    Barcode = request.Barcode ?? string.Empty,
                    ExpenseTime = DateTime.Now,
                    OperatorName = request.OperatorName ?? "system",
                    IsPushedToPatient = false,
                    Remarks = request.Remarks ?? string.Empty,
                    CreateTime = DateTime.Now,
                    CreateUser = request.OperatorName ?? "system"
                };

                // 保存费用记录
                using (var transaction = dbContext.Database.BeginTransaction())
                {
                    try
                    {
                        // 保存费用记录
                        expenseRepository.Create(expense);

                        // 更新预交款余额
                        var prepayment = prepaymentRepository.GetALL()
                            .Where(p => p.MedicalCard == request.MedicalCard && !p.IsDeleted)
                            .OrderByDescending(p => p.CreateTime)
                            .FirstOrDefault();

                        if (prepayment != null)
                        {
                            // 更新已用金额和剩余金额
                            prepayment.UsedPrice += totalAmount;
                            prepayment.ResiduePrice -= totalAmount;
                            prepaymentRepository.Update(prepayment);

                            logger.LogInformation($"已更新预交款记录，ID：{prepayment.Id}，已用金额：{prepayment.UsedPrice}，剩余金额：{prepayment.ResiduePrice}");
                        }
                        else
                        {
                            logger.LogWarning($"未找到患者{request.PatientName}的预交款记录");
                        }

                        // 提交事务
                        transaction.Commit();
                    }
                    catch (Exception ex)
                    {
                        // 回滚事务
                        transaction.Rollback();
                        throw new Exception("保存费用记录时发生错误", ex);
                    }
                }

                logger.LogInformation($"住院费用记录创建成功，ID：{expense.Id}");

                result.Data = expense.Id;
                result.Code = APIEnums.Success;
                result.Msg = "创建住院费用记录成功";
            }
            catch (Exception ex)
            {
                logger.LogError(ex, "创建住院费用记录时发生异常");
                result.Code = APIEnums.Fail;
                result.Msg = $"创建住院费用记录失败：{ex.Message}";
            }

            return Task.FromResult(result);
        }
    }
} 